package edu.bbu.commonproject.desktop.gui.controller.concrete;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.util.ArrayList;

import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JLabel;
import javax.swing.JMenuItem;
import javax.swing.JPasswordField;
import javax.swing.JRadioButton;
import javax.swing.JTextField;
import javax.swing.JTree;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreePath;

import edu.bbu.commonproject.desktop.client.exceptions.DataBaseErrorException;
import edu.bbu.commonproject.desktop.client.exceptions.NoConnectionException;
import edu.bbu.commonproject.desktop.client.exceptions.WrongUserDataException;
import edu.bbu.commonproject.desktop.client.model.DirectoryPOJO;
import edu.bbu.commonproject.desktop.client.model.UserPOJO;
import edu.bbu.commonproject.desktop.client.services.DirectoryCLTServices;
import edu.bbu.commonproject.desktop.gui.controller.BaseController;
import edu.bbu.commonproject.desktop.gui.controller.utils.CryptingService;
import edu.bbu.commonproject.desktop.gui.controller.utils.StringFormatter;
import edu.bbu.commonproject.desktop.gui.controller.utils.UserProperties;
import edu.bbu.commonproject.desktop.gui.view.SetupInterface;
import edu.bbu.commonproject.desktop.gui.view.swing.base.BaseFrame;
import edu.bbu.commonproject.desktop.gui.view.swing.file.lister.tree.DirectoryTree;
import edu.bbu.commonproject.desktop.gui.view.swing.file.lister.utils.GeneralDialog;
import edu.bbu.commonproject.desktop.gui.view.swing.utils.AboutFrame;
import edu.bbu.commonproject.desktop.gui.view.swing.utils.HelpFrame;

/**
 * The setup controller that extends from the BaseController class. 
 */
public class SetupController extends BaseController
{
	/** The base frame controller. */
	private BaseFrameController baseFrameController;
	
	/** The encrypting service.*/
	private CryptingService cryptingService;
	
	/** The setup interface.*/
	private SetupInterface setupInterface;
	
	/**
	 * The setup controller.
	 * @param baseFrameController the base frame controller.
	 * @param setupInterface the setup interface.
	 */
	public SetupController(BaseFrameController baseFrameController, SetupInterface setupInterface)
	{
		this.baseFrameController = baseFrameController;
		this.setupInterface = setupInterface;
		
		try
		{
			this.cryptingService = new CryptingService();
		}
		catch (InvalidKeyException | NoSuchAlgorithmException | UnsupportedEncodingException | InvalidKeySpecException | NoSuchPaddingException e)
		{
			e.printStackTrace();
		}
		
		setListeners();
	}
	
	/**
	 * Setting on the listeners.
	 */
	private void setListeners()
	{
		setNavigationMenuListeners();
		
		setSyncViewListeners();
		setPrivacyViewListeners();
		
		setMenuBarListeners();
	}
	
	/**
	 * Setting on the navigation menu listeners.
	 */
	private void setNavigationMenuListeners()
	{
		((JButton)setupInterface.getBackToFilesButton()).addActionListener(new ActionListener()
		{
			public void actionPerformed(ActionEvent e)
			{
				baseFrameController.getBaseFrame().moveToFront(BaseFrame.FILES_PANEL);
			}
		});
		
		((JButton)setupInterface.getPrivatcySetupButton()).addActionListener(new ActionListener()
		{
			public void actionPerformed(ActionEvent e)
			{
				loadPrivacyView();
			}
		});
		
		((JButton)setupInterface.getSynchronizeSetupButton()).addActionListener(new ActionListener()
		{
			public void actionPerformed(ActionEvent e)
			{
				loadSyncView();
			}
		});
	}
	
	/**
	 * Setting on the synchronization view listeners.
	 */
	private void setSyncViewListeners()
	{
		((JButton)setupInterface.getLocalsyncDirectoryChoose()).addActionListener(new ActionListener()
		{
			public void actionPerformed(ActionEvent arg0)
			{
				openLocalRootTree();
			}
		});
		
		((JButton)setupInterface.getServersyncDirectoryChoose()).addActionListener(new ActionListener()
		{
			public void actionPerformed(ActionEvent arg0)
			{
				openServerRootTree();
			}
		});
		
		((JButton)setupInterface.getSyncSaveButton()).addActionListener(new ActionListener()
		{
			public void actionPerformed(ActionEvent arg0)
			{
				if(((JCheckBox)setupInterface.getAutoSyncSetup()).isSelected())
				{
					userProperties.setValue(UserProperties.SYNC_ACTIVE, "true");
				}
				else 
				{
					userProperties.setValue(UserProperties.SYNC_ACTIVE, "false");
				}
				
				if(((JRadioButton) setupInterface.getOneWaySync()).isSelected())
				{
					userProperties.setValue(UserProperties.SYNC_TYPE, "1");
				}
				else
				{
					userProperties.setValue(UserProperties.SYNC_TYPE, "2");
				}
				
				String localAppended = ((JTextField) setupInterface.getLocalSyncFolderField()).getText();
				String serverAppended = ((JTextField) setupInterface.getServerSyncFolderField()).getText();
				
				String localPath = stringFormatter.parentDirectoryFormat(localAppended, File.separator);
				String localDirecotry = stringFormatter.getLastDirectoryInPath(localAppended, File.separator);
				
				userProperties.setValue(UserProperties.SYNC_LOCAL_DIRECTORY, localDirecotry);
				userProperties.setValue(UserProperties.SYNC_LOCAL_PATH, localPath);
						
				String serverPath = stringFormatter.parentDirectoryFormat(serverAppended, DirectoryCLTServices.separator);
				String serverDirecotry = stringFormatter.getLastDirectoryInPath(serverAppended, DirectoryCLTServices.separator);
				
				DirectoryPOJO directoryPOJO = new DirectoryPOJO();
				directoryPOJO.setParrentDirectory(serverPath);
				directoryPOJO.setDirectoryName(serverDirecotry);
				directoryPOJO.setOwner(userProperties.getValue(UserProperties.USERNAME));
				
				try
				{
					directoryServices.setSyncDirectory(directoryPOJO);
				}
				catch (NoConnectionException | DataBaseErrorException e)
				{
					new GeneralDialog(baseFrameController.getBaseFrame(), "Setup confirmation", "Error occured!Synchronizing setups are not saved!", GeneralDialog.ERROR_DIALOG).showDialog();
					return;
				}
				
				userProperties.save();
				
				new GeneralDialog(baseFrameController.getBaseFrame(), "Setup confirmation", "Synchronizing setups are saved!", GeneralDialog.ACCEPT_DIALOG).showDialog();
			}
		});
	}

	/**
	 * Setting on the privacy view listeners.
	 */
	private void setPrivacyViewListeners()
	{
		((JButton)setupInterface.getPrivacySaveButton()).addActionListener(new ActionListener()
		{
			public void actionPerformed(ActionEvent arg0)
			{
				((JLabel) setupInterface.getPasswordErrorLabel()).setVisible(false);
				((JLabel) setupInterface.getCurrentPasswordErrorLabel()).setVisible(false);
				
				if(((JCheckBox) setupInterface.getDeleteUserAccount()).isSelected())
				{
					String userName = userProperties.getValue(UserProperties.USERNAME);
					String password = new String(((JPasswordField) setupInterface.getCurrentPasswordField()).getPassword());
					
					try
					{
						String cryptedPassword = cryptingService.encrypt(password);
						UserPOJO userPOJO = new UserPOJO(userName, cryptedPassword);
						
						userServices.deleteUser(userPOJO);
						
						new GeneralDialog(baseFrameController.getBaseFrame(), "Delete confirmation", "Your account was deleted successfully!", GeneralDialog.ACCEPT_DIALOG).showDialog();
						
						baseFrameController.getFileListController().logoutUser();
						
					}
					catch (WrongUserDataException e)
					{
						((JLabel) setupInterface.getCurrentPasswordErrorLabel()).setVisible(true);
					}
					catch (DataBaseErrorException | UnsupportedEncodingException | IllegalBlockSizeException | BadPaddingException e)
					{
						new GeneralDialog(baseFrameController.getBaseFrame(), "Privacy error", "Unexpected error occured!", GeneralDialog.ERROR_DIALOG).showDialog();
					}
					catch (NoConnectionException e)
					{
						new GeneralDialog(baseFrameController.getBaseFrame(), "Connection error", "Connection dropped!", GeneralDialog.WARNING_DIALOG).showDialog();	
					}
					
					return;
				}
				else 
				{
					String newPassword = new String(((JPasswordField) setupInterface.getNewPasswordField()).getPassword());
					String newPasswordConfirmation = new String(((JPasswordField) setupInterface.getNewPasswordConfirmationField()).getPassword());
					
					if(newPassword.length() < 6 || !newPassword.equals(newPasswordConfirmation))
					{
						((JLabel) setupInterface.getPasswordErrorLabel()).setVisible(true);
						return;
					}
					
					String userName = userProperties.getValue(UserProperties.USERNAME);
					String password = new String(((JPasswordField) setupInterface.getCurrentPasswordField()).getPassword());
					
					try
					{
						String cryptedPassword = cryptingService.encrypt(password);
						String newCryptedPassword = cryptingService.encrypt(newPassword);
						
						UserPOJO userPOJO = new UserPOJO(userName, cryptedPassword);
						
						userServices.changePassword(userPOJO, newCryptedPassword);
						
						new GeneralDialog(baseFrameController.getBaseFrame(), "Password confirmation", "Your password was changed successfully!", GeneralDialog.ACCEPT_DIALOG).showDialog();
					}
					catch (WrongUserDataException e)
					{
						((JLabel) setupInterface.getCurrentPasswordErrorLabel()).setVisible(true);
					}
					catch (DataBaseErrorException | UnsupportedEncodingException | IllegalBlockSizeException | BadPaddingException e)
					{
						new GeneralDialog(baseFrameController.getBaseFrame(), "Privacy error", "Unexpected error occured!", GeneralDialog.ERROR_DIALOG).showDialog();
					}
					catch (NoConnectionException e)
					{
						new GeneralDialog(baseFrameController.getBaseFrame(), "Connection error", "Connection dropped!", GeneralDialog.WARNING_DIALOG).showDialog();	
					}
					
				}
			}
		});
	}
	
	/**
	 * Setting on the menu bar listeners.
	 */
	private void setMenuBarListeners()
	{
		((JMenuItem) setupInterface.getLogoutMenuItem()).addActionListener(new ActionListener()
		{
			public void actionPerformed(ActionEvent arg0)
			{
				baseFrameController.getFileListController().logoutUser();
			}
		});
		
		((JMenuItem) setupInterface.getExitMenuItem()).addActionListener(new ActionListener()
		{
			public void actionPerformed(ActionEvent arg0)
			{
				System.exit(0);
			}
		});
		
		((JMenuItem) setupInterface.getHelpMenuItem()).addActionListener(new ActionListener()
		{
			public void actionPerformed(ActionEvent e)
			{
				new HelpFrame();
			}
		});
		
		((JMenuItem) setupInterface.getAboutMenuItem()).addActionListener(new ActionListener()
		{
			public void actionPerformed(ActionEvent e)
			{
				new AboutFrame();
			}
		});
	}
	
	/**
	 * Setting synchronization properties.
	 */
	private void setSyncProperties()
	{
		int syncType = Integer.parseInt(userProperties.getValue(UserProperties.SYNC_TYPE));
		String localSyncPath = userProperties.getValue(UserProperties.SYNC_LOCAL_PATH);
		String localSyncDirectory = userProperties.getValue(UserProperties.SYNC_LOCAL_DIRECTORY);
		
		DirectoryPOJO directoryPOJO = new DirectoryPOJO();
		
		try
		{
			directoryPOJO = directoryServices.getSyncDirectory(userProperties.getValue(UserProperties.USERNAME));
		}
		catch (NoConnectionException | WrongUserDataException | DataBaseErrorException e)
		{
			new GeneralDialog(baseFrameController.getBaseFrame(), "Setup error", "Error occured when loading the server sync directoryes.", GeneralDialog.ERROR_DIALOG).showDialog();
			return;
		}
		
		String serverSyncPath = directoryPOJO.getParrentDirectory();
		String serverSyncDirectory = directoryPOJO.getDirectoryName();
		
		
		boolean isAutoSyncActive = Boolean.parseBoolean(userProperties.getValue(UserProperties.SYNC_ACTIVE));
		
		((JCheckBox)setupInterface.getAutoSyncSetup()).setSelected(isAutoSyncActive);

		if(syncType == 1)
		{
			((JRadioButton) setupInterface.getOneWaySync()).setSelected(true);
		}
		else
		{
			((JRadioButton) setupInterface.getTwoWaySync()).setSelected(true);
		}
		
		((JTextField) setupInterface.getLocalSyncFolderField()).setText(localSyncPath  + localSyncDirectory + File.separator);
		((JTextField) setupInterface.getServerSyncFolderField()).setText(serverSyncPath + serverSyncDirectory + DirectoryCLTServices.separator);
	}
	
	/**
	 * Opening the local root tree.
	 */
	private void openLocalRootTree()
	{
		DirectoryTree directoryTree = new DirectoryTree(baseFrameController.getBaseFrame(), File.separator);
		
		directoryTree.setNodeClickListener(new MouseAdapter()
		{
			public void mouseClicked(MouseEvent e)
			{
				TreePath treePath = ((JTree) e.getSource()).getPathForLocation(e.getX(), e.getY());
				
				if(treePath != null)
				{
					Object[] treePathObjects = treePath.getPath();
					
					DefaultMutableTreeNode parrentNode = (DefaultMutableTreeNode) treePath.getLastPathComponent();
					parrentNode.removeAllChildren();
					String parrentDirectory = treePathObjects[1].toString();
					
					for(int i = 2; i < treePathObjects.length; i++)
					{
						parrentDirectory += treePathObjects[i].toString() + File.separator;
					}
					
					ArrayList<String> directoryList;
					
					try
					{
						directoryList = baseFrameController.getFileListController().getLocalDirectoryes(parrentDirectory, "");
					}
					catch (FileNotFoundException ex) 
					{ 
						return;
					}
					
					for (String directory : directoryList)
					{
						DefaultMutableTreeNode childNode = new DefaultMutableTreeNode(directory);
						parrentNode.add(childNode);
					}
				}
			}
		});
		
		File[] roots = File.listRoots();
		
		for (File file : roots)
		{
			directoryTree.addToRoot(new DefaultMutableTreeNode(file.getPath()));
		}
		
		directoryTree.showDialog();
		
		if(directoryTree.getAnswer() == DirectoryTree.SELECT_ANSWER)
		{
			((JTextField) setupInterface.getLocalSyncFolderField()).setText(directoryTree.getSelectedDirectory());
		}
		
	}
	
	/**
	 * Opening the server root tree.
	 */
	private void openServerRootTree()
	{
		DirectoryTree directoryTree = new DirectoryTree(baseFrameController.getBaseFrame(), DirectoryCLTServices.separator);
		
		directoryTree.setNodeClickListener(new MouseAdapter()
		{
			public void mouseClicked(MouseEvent e)
			{
				TreePath treePath = ((JTree) e.getSource()).getPathForLocation(e.getX(), e.getY());
				
				if(treePath != null)
				{
					Object[] treePathObjects = treePath.getPath();
					
					DefaultMutableTreeNode parrentNode = (DefaultMutableTreeNode) treePath.getLastPathComponent();
					parrentNode.removeAllChildren();
					String parrentDirectory = "";
					
					
					for(int i = 1; i < treePathObjects.length; i++)
					{
						parrentDirectory += treePathObjects[i].toString() + DirectoryCLTServices.separator;
					}
					
					String parrentPath = stringFormatter.parentDirectoryFormat(parrentDirectory, DirectoryCLTServices.separator);
					String directoryName = stringFormatter.getLastDirectoryInPath(parrentDirectory, DirectoryCLTServices.separator);
					
					ArrayList<String> directoryList;
					try
					{
						directoryList = baseFrameController.getFileListController().getServerDirectoryes(parrentPath, directoryName);
					}
					catch (FileNotFoundException ex)
					{
						return;
					}
					
					for (String directory : directoryList)
					{
						DefaultMutableTreeNode childNode = new DefaultMutableTreeNode(directory);
						parrentNode.add(childNode);
					}
				}
			}
		});
		
		DirectoryPOJO serverDirectory;
		
		try
		{
			serverDirectory = directoryServices.getBaseDirectory(userProperties.getValue(UserProperties.USERNAME));
		}
		catch (NoConnectionException e)
		{
			return;
		}
		
		directoryTree.addToRoot(new DefaultMutableTreeNode(serverDirectory));
		directoryTree.showDialog();
		
		if(directoryTree.getAnswer() == DirectoryTree.SELECT_ANSWER)
		{
			((JTextField) setupInterface.getServerSyncFolderField()).setText(directoryTree.getSelectedDirectory());
		}
	}

	/**
	 * Set privacy properties.
	 */
	private void setPrivacyProperties()
	{
		((JPasswordField) setupInterface.getNewPasswordField()).setText("");
		((JPasswordField) setupInterface.getNewPasswordConfirmationField()).setText("");
		((JLabel) setupInterface.getPasswordErrorLabel()).setVisible(false);
		((JCheckBox) setupInterface.getDeleteUserAccount()).setSelected(false);
		((JPasswordField) setupInterface.getCurrentPasswordField()).setText("");
		((JLabel) setupInterface.getCurrentPasswordErrorLabel()).setVisible(false);
	}
	
	/**
	 * Loading synchronization view.
	 */
	public void loadSyncView()
	{
		setSyncProperties();
		setupInterface.moveToFront(SetupInterface.SYNC_SETUP_PANEL);
	}
	
	/**
	 * Loading privacy view.
	 */
	public void loadPrivacyView()
	{
		setPrivacyProperties();
		setupInterface.moveToFront(SetupInterface.PRIVACY_SETUP_PANEL);
	}
}
